`timescale       1ns/100ps
`default_nettype none

//***********************************************************
module pixel_gray_reader(
    // system signal
    input  wire         I_sclk,             // 125M
    input  wire         I_sdram_clk,        // now is 125M, could be bigger
    input  wire         I_rst_n,
    
    output wire         O_coe_ram_clk,
    output wire         O_coe_ram_wren_r,
    output wire         O_coe_ram_wren_g,
    output wire         O_coe_ram_wren_b,
    output wire[31:0]   O_coe_ram_data,
    output wire[7:0]    O_coe_ram_addr,

    //buf 
    output wire         O_ram_wclk,
    output wire         O_ram_wren,
    output wire [9:0]   O_ram_addr,
    output wire [23:0]  O_ram_data,

    input  wire         I_sdram_req,
    input  wire [20:0]  I_cfg_sdram_addr   ,// 
    input  wire [9:0]   I_cfg_sdram_len    ,//现在必需是4的倍数
    input  wire [2:0]   I_cfg_sdram_req_cnt,//读几行 从0开始计数 相当有几折
    input  wire [20:0]  I_cfg_sdram_add    ,//每行之间的地址差
    input  wire [20:0]  I_cfg_sdram_col_add,
    input  wire [20:0]  I_cfg_sdram_add1   ,//色度校正中每个分量的地址差,或者h64_max
    input  wire [1:0]   I_cfg_sdram_mode   ,// 0:像素 1：亮度校正 2：色度校正 
    input  wire         I_cfg_sdram_dir    ,// 0：按行读  1：按列读
    output wire         O_sdram_busy       ,//sdram读模块忙
    output wire         O_sdram_coe_busy   ,//sdram读模块忙
    // input  wire         I_cfg_sdram_data_sel,//读回的数据缓存到那个buf

    // sdram mux
    output wire         O_mux_req,
    input  wire         I_mux_ack,
    input  wire         I_mux_irq,     //中断，表示有更高优先级的模块正在请求SDRAM控制权
    output wire         O_mux_cs_n,
    output wire         O_mux_ras_n,
    output wire         O_mux_cas_n,
    output wire         O_mux_we_n,
    output wire [1:0]   O_mux_ba,
    output wire [10:0]  O_mux_addr,
    output wire [31:0]  O_mux_dq_out,
    input  wire [31:0]  I_mux_dq_in,
    output wire         O_mux_dq_oe,
    output wire [3:0]   O_mux_dqm
    );
//***********************************************************
`include "../led_display/sdram_common.vh" 
localparam
    RL = 3 + SD_MR_CL;  // read data latency
    
// wait count
localparam
    WAIT_TIME = (1 << SD_MR_BL) + DELAY_RP - 1  -1; //确保突发4完成后进入等待时间

// fsm
localparam [8:0]
    IDLE  = 1,
    PREP  = 1<<1,
    ACT   = 1<<2,
    NOP0  = 1<<3,
    NOP1  = 1<<4,
    READ  = 1<<5,
    WAIT  = 1<<6,
    WAIT1 = 1<<7,
    LOOP  = 1<<8;

localparam 
    IDLE_ID  = 0,
    PREP_ID  = 1,
    ACT_ID   = 2,
    NOP0_ID  = 3,
    NOP1_ID  = 4,
    READ_ID  = 5,
    WAIT_ID  = 6,
    WAIT1_ID = 7,
    LOOP_ID  = 8;

localparam
    LANDSCAPE = 0;
//***********************************************************
//------------------------Local signal-------------------
// read request (@I_sclk)
reg         busy;
reg  [1:0]  req_sr;
reg  [3:0]  done_sr;

// fsm (@I_sdram_clk)
reg  [8:0]  state;
reg  [8:0]  next;
reg  [3:0]  start_sr;
reg  [1:0]  over_sr;
reg  [3:0]  delay_cnt;
reg         first_act; // 第一次ACT

// sdram mux
reg         mux_req;
reg  [3:0]  mux_cmd;
reg  [1:0]  mux_ba;
reg  [10:0] mux_addr;
reg  [31:0] mux_dq_out;

reg  [3:0]  mux_dqm;


reg  [9:0]  data_cnt;
reg  [2:0]  data_cnt_t;
reg         data_cnt_0 /* synthesis keep */ ;

reg  [20:0] sdram_addr;
reg  [20:0] sdram_addr_r;
reg         sdram_addr_7_2 /* synthesis keep */;

// ram
reg         ram_wren;
reg  [9:0]  ram_addr;
reg  [31:0] ram_data;
wire [31:0] ram_q;

// write ram
reg  [RL:0] read_sr;

assign O_sdram_busy = busy;
assign O_sdram_coe_busy = I_cfg_sdram_mode==0 ? 0: busy; //正在读校正数据

reg [2:0]req_cnt;

reg [1:0]coe_state;
reg [1:0]coe_state_r1;
reg [1:0]coe_state_r2;
reg [1:0]coe_state_r3;
reg [1:0]coe_state_r4;
//busy
always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        busy <= 'b0;
    else if(busy==0 && I_sdram_req==1)
        busy <= 1'b1;
    else if (done_sr[3:2] == 2'b01)
        busy <= 1'b0;
end
//req_sr
always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        req_sr <= 'b0;
    else if(busy==0 && I_sdram_req==1)
        req_sr <= 2'b11;
    else
        req_sr <= req_sr << 1;
end
//done_sr
always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        done_sr <= 'b0;
    else
        done_sr <= {done_sr[2:0], over_sr[1]};
end

// start_sr
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        start_sr <= 1'b0;
    else
        start_sr <= {start_sr[2:0], req_sr[1]};
end

// over_sr
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        over_sr <= 'b0;
    else if (state == LOOP )begin
        if( data_cnt_0 && req_cnt == I_cfg_sdram_req_cnt)begin
            if( I_cfg_sdram_mode[1] == 'b0)
               over_sr <= 2'b11;
            else if(coe_state == 2'd2 )
               over_sr <= 2'b11;
            else 
                over_sr <= over_sr << 1;
         end
         else 
             over_sr <= over_sr << 1;
    end
    else
        over_sr <= over_sr << 1;
end

//***********************************************************
//{{{+++++++++++++++++++++fsm++++++++++++++++++++++++++++
//state
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        state <= IDLE;
    else
    case (state)
        IDLE: begin
            if (start_sr[3])
                state <= PREP;
            else
                state <= IDLE;
        end

        PREP: begin
            state <= ACT;
        end

        ACT: begin
            if (!first_act)
                state <= NOP0;
            else if (I_mux_ack)
                state <= NOP1;
            else
                state <= ACT;
        end

        NOP0: begin
            state <= NOP1; 
        end
        
        NOP1:begin
            // if(I_cfg_sdram_dir=='d0)
                state <= READ;
            // else 
                // state <= READ1;
        end

        READ:begin
           // if (data_cnt_0|| I_mux_irq)
               // state <= WAIT;
           // else 
               // state <= ACT;
               
            // if (data_cnt_0  || I_mux_irq )
            if (data_cnt_0 || I_mux_irq )
                state <= WAIT;
            else if(I_cfg_sdram_dir=='d0 )begin
                state <= ACT;
            end
            else if(sdram_addr_7_2)
                state <= WAIT;
                
        end
        
        // READ1:begin
            // if (data_cnt_0 || I_mux_irq || sdram_addr_7_2 )
                // state <= WAIT;
        // end

        WAIT: begin
            if (delay_cnt >= WAIT_TIME)
                state <= WAIT1;
            else
                state <= WAIT;
        end
        
        WAIT1: begin
            state <= LOOP;
        end

        LOOP: begin
            // if (data_cnt_0)begin
            if (data_cnt_0)begin
                // if( I_cfg_sdram_mode == 'd0 || I_cfg_sdram_mode == 'd1 )begin
                    // if(req_cnt == I_cfg_sdram_req_cnt)
                        // state <= IDLE;
                    // else 
                        // state <= ACT;
                // end
                // else if(coe_state == 2'd2 && req_cnt == I_cfg_sdram_req_cnt)
                    // state <= IDLE;
                // else 
                    // state <= ACT;
                    
                if(req_cnt == I_cfg_sdram_req_cnt)begin
                    if( I_cfg_sdram_mode[1] == 'b0)
                        state <= IDLE;
                    else if(coe_state == 2'd2 )
                        state <= IDLE;
                    else 
                        state <= ACT;
                end
                else 
                    state <= ACT;
                    
            end
            else
                state <= ACT;
        end
        
        default: begin
            state <= IDLE;
        end
    endcase
end


always @(posedge I_sdram_clk) begin
    if (state[IDLE_ID] )
        req_cnt <= 'd0;
    else if (state[LOOP_ID] && data_cnt_0)begin
        if(req_cnt == I_cfg_sdram_req_cnt)
            req_cnt <= 'd0;
         else
            req_cnt <= req_cnt + 'd1;
    end
end

// first_act
always @(posedge I_sdram_clk) begin
    if (state[IDLE_ID] || state[LOOP_ID])
        first_act <= 1'b1;
    else if (state[READ_ID] )
        first_act <= 1'b0;
end


// delay_cnt
always @(posedge I_sdram_clk ) begin
    if (state[READ_ID])
        delay_cnt <= 'd0;
    else
        delay_cnt <= delay_cnt + 1'b1;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++sdram mux++++++++++++++++++++++
assign O_mux_req    = mux_req;
assign O_mux_cs_n   = mux_cmd[3];
assign O_mux_ras_n  = mux_cmd[2];
assign O_mux_cas_n  = mux_cmd[1];
assign O_mux_we_n   = mux_cmd[0];
assign O_mux_ba     = mux_ba;
assign O_mux_addr   = mux_addr;
assign O_mux_dq_out = 'd0;
assign O_mux_dq_oe  = 'd0;
// assign O_mux_dqm    = 1'b0;
assign O_mux_dqm    = mux_dqm;

// mux_req
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        mux_req <= 1'b0;
    else if (state[ACT_ID])
        mux_req <= 1'b1;
    else if (state[LOOP_ID])
        mux_req <= 1'b0;
end

// mux_cmd
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        mux_cmd <= SD_CMD_NOP;
    else if (state[ACT_ID]) begin
        if (first_act & I_mux_ack)
            mux_cmd <= SD_CMD_NOP;
        else
            mux_cmd <= SD_CMD_ACT;
    end
    else if (state[READ_ID])
        mux_cmd <= SD_CMD_READ;
    else
        mux_cmd <= SD_CMD_NOP;
end

// mux_ba
always @(posedge I_sdram_clk) begin
    if (state[IDLE_ID])
        sdram_addr[20:0] <= I_cfg_sdram_addr[20:0];
    else if( state[READ_ID])begin
        case(I_cfg_sdram_dir)
        'd1:begin //按列读
            sdram_addr[1:0] <= sdram_addr[1:0] ;
            sdram_addr[7:2] <= sdram_addr[7:2] + 1'd1;
            sdram_addr[11:8] <= sdram_addr[11:8];

            if(sdram_addr_7_2)
                sdram_addr[17:12]   <= sdram_addr[17:12] + I_cfg_sdram_col_add[17:12];
            else
                sdram_addr[17:12]   <= sdram_addr[17:12] ;
            sdram_addr[20:18]   <= sdram_addr[20:18] ;
        end
        
        default:begin //按行读
            sdram_addr[1:0]     <= 'b0 ; 
            sdram_addr[7:2]     <= sdram_addr[7:2];
            sdram_addr[15:8]    <= sdram_addr[15:8] + 1'b1;
            sdram_addr[17:16]   <= sdram_addr[17:16] ;
            sdram_addr[20:18]   <= sdram_addr[20:18] ;
        end
        endcase
    end
    
   // else if( state[READ_ID])begin
           // sdram_addr[1:0]     <= 'b0 ; 
           // sdram_addr[7:2]     <= sdram_addr[7:2];
           // sdram_addr[15:8]    <= sdram_addr[15:8] + 1'b1;
           // sdram_addr[17:16]   <= sdram_addr[17:16] ;
           // sdram_addr[20:18]   <= sdram_addr[20:18] ;
   // end
   // else if( state[READ1_ID])begin
           // sdram_addr[1:0] <= sdram_addr[1:0] ;
           // sdram_addr[7:2] <= sdram_addr[7:2] + 1'd1;
           // sdram_addr[11:8] <= sdram_addr[11:8];
           // if(sdram_addr_7_2)
               // sdram_addr[17:12]   <= sdram_addr[17:12] + I_cfg_sdram_col_add[17:12];
           // else
               // sdram_addr[17:12]   <= sdram_addr[17:12] ;
           // sdram_addr[20:18]   <= sdram_addr[20:18] ;
   // end
   
    else if(state[LOOP_ID] && data_cnt_0)begin
        sdram_addr[20:0] <= sdram_addr_r[20:0];
    end
end

always@(*)begin
    if ( sdram_addr[7:2] == 6'h3f )
        sdram_addr_7_2 = 1;
    else 
        sdram_addr_7_2 = 0;
end

//计算下一折地址
reg [20:0]sdram_addr_next_line;   //下折的地址
reg [6:0] sdram_addr_next_line_count;   //行模式时，低位相加
always @(posedge I_sdram_clk or negedge I_rst_n)
    if ( !I_rst_n )
        sdram_addr_next_line_count <= 'd0;
    else if(state[IDLE_ID])
        sdram_addr_next_line_count <= 'd0;
    else if (state[READ_ID])
        case(I_cfg_sdram_dir)
            'd1:begin//按列读 
                sdram_addr_next_line_count <= {sdram_addr_r[11:8] , sdram_addr_r[1:0]} + {I_cfg_sdram_add[11:8] , I_cfg_sdram_add[1:0]};
            end
            default: begin//按行读
                sdram_addr_next_line_count <= sdram_addr_r[7:2] + I_cfg_sdram_add[7:2];
            end
         endcase
   

always @(posedge I_sdram_clk or negedge I_rst_n)
    if ( !I_rst_n )
        sdram_addr_next_line <= 'd0;
    else if (state[IDLE_ID])
        sdram_addr_next_line <= 'd0;
    else if(state[WAIT_ID])begin
        case(I_cfg_sdram_dir)
            'd1:begin//按列读
                sdram_addr_next_line[1:0] <=  sdram_addr_next_line_count[1:0];
                sdram_addr_next_line[11:8] <=  sdram_addr_next_line_count[5:2];
                sdram_addr_next_line[20:12] <= sdram_addr_r[20:12] + I_cfg_sdram_add[20:12] + sdram_addr_next_line_count[6]  ;//计算折行
            end
            default: begin//按行读
                 sdram_addr_next_line[7:2] <=  sdram_addr_next_line_count[5:0];
                
                 if(sdram_addr_next_line_count[6])
                    sdram_addr_next_line[20:12] <= sdram_addr_r[20:12] + I_cfg_sdram_add[20:12] + I_cfg_sdram_col_add[17:12]; //计算折行
                 else 
                    sdram_addr_next_line[20:12] <= sdram_addr_r[20:12] + I_cfg_sdram_add[20:12] ;
            end
         endcase
    end


always @(posedge I_sdram_clk)
    if (state[IDLE_ID])
        sdram_addr_r[20:0] <= I_cfg_sdram_addr[20:0];
    // else if(state[WAIT_ID] && delay_cnt >= (WAIT_TIME) && data_cnt_0)begin
     else if(state[WAIT1_ID] && data_cnt_0 )begin
        if(req_cnt == I_cfg_sdram_req_cnt && I_cfg_sdram_mode == 'd2 )begin //色度校正分量切换
             if(coe_state==0)begin
                sdram_addr_r[11:0] <= I_cfg_sdram_addr[11:0];
                sdram_addr_r[20:12] <= I_cfg_sdram_addr[20:12] + I_cfg_sdram_add1[20:12]; //计算色度分量地址
             end
             else if(coe_state==1) begin
                sdram_addr_r[11:0] <= I_cfg_sdram_addr[11:0];
                sdram_addr_r[20:12] <= I_cfg_sdram_addr[20:12] + I_cfg_sdram_add1[20:12] + I_cfg_sdram_add1[20:12] ;
                // sdram_addr_r[20:12] <= I_cfg_sdram_addr[20:12] + {I_cfg_sdram_add1[20:12],1'd0};
             end
        end 
        else 
            // case(I_cfg_sdram_dir)
                // 'd1:begin//按列读
                    // sdram_addr_r[1:0] <=  sdram_addr_next_line_count[1:0];
                    // sdram_addr_r[11:8] <=  sdram_addr_next_line_count[5:2];
                    // sdram_addr_r[20:12] <= sdram_addr_r[20:12] + I_cfg_sdram_add[20:12] + sdram_addr_next_line_count[6]  ;//计算折行
                // end
                // default: begin//按行读
                     // sdram_addr_r[7:2] <=  sdram_addr_next_line_count[5:0];
                    
                     // if(sdram_addr_next_line_count[6])
                        // sdram_addr_r[20:12] <= sdram_addr_r[20:12] + I_cfg_sdram_add[20:12] + I_cfg_sdram_col_add[17:12]; //计算折行
                     // else 
                        // sdram_addr_r[20:12] <= sdram_addr_r[20:12] + I_cfg_sdram_add[20:12] ;
                // end
             // endcase
            sdram_addr_r[20:0] <=  sdram_addr_next_line ;
        
        
            // sdram_addr_r[20:0] <= sdram_addr_r[20:0] + I_cfg_sdram_add[20:0]; //计算折行
            
            
         // if(I_cfg_sdram_mode == 'd2 )begin //色度校正分量切换
             // if(coe_state==0)
                // sdram_addr_r[20:0] <= I_cfg_sdram_addr[20:0] + I_cfg_sdram_add1[20:0]; //计算色度分量地址
             // else if(coe_state==1)
                // sdram_addr_r[20:0] <= I_cfg_sdram_addr[20:0] + {I_cfg_sdram_add1[20:0],1'd0};
        // end 
    end

// mux_ba
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        mux_ba <= 'b0;
    else if ( state[ACT_ID] || state[READ_ID] ) 
        mux_ba <= sdram_addr[9:8];
end

// mux_addr
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        mux_addr <= 'b0;
    else if (state[ACT_ID])
        mux_addr <= {sdram_addr[20:10]};
    else if (state[READ_ID])begin
        mux_addr <= {1'b1, 2'b00 , sdram_addr[7:0]};
    end
end

reg [3:0]rw_addr_en;
reg [3:0]rw_len_en;
always@(*)begin
    if(data_cnt==0)
        data_cnt_0 <= 'b1 ;
    else
        data_cnt_0 <= 'b0;
end

reg [2:0]data_wr_len;
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n) 
        data_wr_len <= 'd4;
    else if ( state[ACT_ID] )
        data_wr_len <= 3'd4 - sdram_addr[1:0] ;
end



always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)begin
        data_cnt <= 'b0;
    end
    else if (state[PREP_ID]) begin
         data_cnt <= I_cfg_sdram_len;
    end
    else if ( state[NOP1_ID] ) begin
        if(I_cfg_sdram_dir == 'd0 )begin
            if(data_cnt_t >= data_wr_len)
                data_cnt <= data_cnt - data_wr_len ;
            else 
                data_cnt <= 'd0 ;
                
        end
        else 
            data_cnt <= data_cnt -'d1;
    end 
    
    else if(state[READ_ID])begin
        if(I_cfg_sdram_dir == 'd1)begin
            // if(data_cnt_0 || I_mux_irq || sdram_addr_7_2)
            if(data_cnt_0 || I_mux_irq || sdram_addr_7_2)
                data_cnt <= data_cnt ;
            else
                data_cnt <= data_cnt -'d1;
        end
    end    
    else if(state[LOOP_ID] && data_cnt_0)
        data_cnt <= I_cfg_sdram_len;
        
end


always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)begin
        data_cnt_t <= 'b0;
    end
    else if(state[ACT_ID]) begin
        if(data_cnt[9:2] != 0)
            data_cnt_t <= 3'b100;
        else 
            data_cnt_t <= {1'b0, data_cnt[1:0]};
    end
end


always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)begin
        rw_len_en <= 4'b0000;
    end
    else if ( state[NOP1_ID] ) begin
        
        if(I_cfg_sdram_dir == 'd0 )begin
                
            case(data_cnt_t[2:0])
            0: rw_len_en[3:0] <= 4'b0000;
            
            1: rw_len_en[3:0] <= 4'b1000;
            
            2: rw_len_en[3:0] <= 4'b1100;
            
            3: rw_len_en[3:0] <= 4'b1110;
            default : rw_len_en[3:0] <= 4'b1111;
            
            endcase    
        end
        else
            rw_len_en[3:0] <= 4'b1000;
    end
    else if(state[READ_ID])begin
        if(I_cfg_sdram_dir == 'd0 )
            rw_len_en[3:0] <= {rw_len_en[2:0] , 1'b0};
        // else if(data_cnt_0 || I_mux_irq || sdram_addr_7_2)
        else if(data_cnt_0 || I_mux_irq || sdram_addr_7_2)
            rw_len_en[3:0] <= 4'b0000;
        else 
            rw_len_en[3:0] <= 4'b1000;
    end
    else begin
        rw_len_en[3:0] <= {rw_len_en[2:0] , 1'b0};
    end
end

always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)begin
        rw_addr_en <= 4'b0000;
    end
    else if ( state[NOP1_ID] ) begin
        if(I_cfg_sdram_dir == 'd0 )
            // rw_addr_en[3:0] <= 4'b1111;
            case(sdram_addr[1:0])
                0:begin
                    rw_addr_en[3:0] <= 4'b1111;
                end
                
                1:begin
                    rw_addr_en[3:0] <= 4'b1110;
                end
                
                2:begin
                    rw_addr_en[3:0] <= 4'b1100;
                end
                
                3:begin
                    rw_addr_en[3:0] <= 4'b1000;
                end
            endcase
        else 
           rw_addr_en[3:0] <= 4'b1000; 
    end
    
    else if(state[READ_ID])begin
        if(I_cfg_sdram_dir == 'd0 )
            rw_addr_en[3:0] <= {rw_addr_en[2:0] , 1'b0};
        else  
            rw_addr_en[3:0] <= 4'b1000;
    end
    else begin
        rw_addr_en[3:0] <= {rw_addr_en[2:0] , 1'b0};
    end
end

always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        mux_dqm <= 'b0;
    else
        mux_dqm <= 'b0;
end

//{{{+++++++++++++++++++++write ram++++++++++++++++++++++
// read_sr
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        read_sr <= 'b0;
    else
        read_sr[RL:0] <= {read_sr[RL-1:0], (rw_addr_en[3] & rw_len_en[3])};
end


// ram_wren
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        ram_wren <= 1'b0;
    else if (read_sr[RL] )
        ram_wren <= 1'b1;
    else
        ram_wren <= 1'b0;
end

// ram_waddr
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        ram_addr <= 'b0;
    else if (state[PREP_ID])
        ram_addr <= 'b0;
    else if(coe_state_r4 != coe_state_r3)
        ram_addr <= 'b0;
    else if (ram_wren  )
        ram_addr <= ram_addr + 1'b1;
end

// ram_data
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        ram_data <= 'b0;
    else if (read_sr[RL]) 
        ram_data <= I_mux_dq_in ;
end

//coe_state
always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)
        coe_state <= 'd3;
    else if (state[IDLE_ID]) begin
        if(I_cfg_sdram_mode == 'd0)
            coe_state <= 'd3;
        else 
            coe_state <= 'd0;
    end
    else if(state[LOOP_ID] && data_cnt_0)begin
        if(I_cfg_sdram_mode != 'd0 && req_cnt == I_cfg_sdram_req_cnt)
            coe_state <= coe_state + 'd1;
    end
end


always @(posedge I_sdram_clk or negedge I_rst_n) begin
    if (!I_rst_n)begin
        coe_state_r1 <= 'd3;
        coe_state_r2 <= 'd3;
        coe_state_r3 <= 'd3;
        coe_state_r4 <= 'd3;
    end
    else begin
        coe_state_r1 <= coe_state;
        coe_state_r2 <= coe_state_r1;
        coe_state_r3 <= coe_state_r2;
        coe_state_r4 <= coe_state_r3;
    end
end


assign O_coe_ram_clk    = I_sdram_clk;
assign O_coe_ram_wren_r = I_cfg_sdram_mode == 2'b1 ? ram_wren : (ram_wren && coe_state_r4 =='d0);
assign O_coe_ram_wren_g = I_cfg_sdram_mode == 2'b1 ? ram_wren : (ram_wren && coe_state_r4 =='d1);
assign O_coe_ram_wren_b = I_cfg_sdram_mode == 2'b1 ? ram_wren : (ram_wren && coe_state_r4 =='d2);
assign O_coe_ram_data   = ram_data;
assign O_coe_ram_addr   = ram_addr[7:0];


assign O_ram_wclk       = I_sdram_clk;
assign O_ram_wren       = ram_wren && coe_state_r4 =='d3;
assign O_ram_addr       = ram_addr[9:0];
assign O_ram_data       = ram_data[23:0];

endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker:
